package com.cskaoyan.java.object._3equals._0introduction;

/**
 * 简单介绍一下equals方法
 * equals方法的声明，比较简单：
 * public boolean equals(Object obj)
 * 仅需要注意两点：
 *      1.方法是有返回值的，返回一个布尔类型的值，真或假。
 *      2.该方法是有参数的，需要传入一个对象（任意一个对象就行）
 *
 * 方法的作用:
 * equals有相同，相等的意思。
 * 所以该方法的作用是，用于指示其他某个对象是否与此对象"相等"。
 * 此对象即调用该equals方法的对象，其它对象即方法实参传入的对象。
 *
 * 既然是比较对象相等，那自然就需要比较的规则才有意义
 * 比较的规则其实就是equals方法体中的代码实现,它的实现就表示一个equals比较相等的规则
 *
 * Object类下equals方法默认的比较规则是:
 *   return (this == obj);
 * 也就是说只有两个对象完全就是同一个对象时,才会返回true
 * 这样的比较规则显然太苛刻了,实际开发中需要更灵活的比较规则,需要在子类中重写这个方法
 *
 * 我们希望的比较对象相等的规则是:
 *      1.如果两个对象不是同种类型的对象,那么就没有可比性,直接返回false
 *      1.如果两个对象是同种类型的对象,那么就进行比较属性的取值,属性的取值如果相等,那就认为对象相等.
 *
 * 对于以上比较规则的equals方法的重写，Java官方为我们提供了官方的要求
 * 称之为equals方法重写的常规协定：
 *      1.自反性：对于任何非空引用值 x，x.equals(x)都应返回 true
 *      2.排他性：当比对的不是同种类型的对象或者是一个null时，默认返回false
 *
 *      3.对称性：对于任何非空引用值 x 和 y，当且仅当y.equals(x) 返回 true 时，x.equals(y) 才应返回true
 *      x=y --> y=x
 *
 *      4.传递性：对于任何非空引用值 x、y 和 z，如果x.equals(y)返回 true，并且 y.equals(z) 返回 true，那么x.equals(z) 应返回 true。
 *      x = y, y = z --> x = z
 *
 *      5.一致性：对于任何非空引用值 x 和 y，多次调用 x.equals(y)始终返回 true 或始终返回 false。
 *      以上三点,只需要依据"成员变量属性的取值"来判断对象相等,就能够自动满足了
 *
 * equals方法的基本使用就如上.
 *
 * @since 14:28
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Student s1 = new Student(18, 100);
        Student s2 = new Student(18, 100);
        Student s3 = s1;
        System.out.println(s1.equals(s2));
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s3));

        String str1 = "hello";
        String str2 = new String("hello");
        System.out.println(str1.equals(str2));
    }
}

class Student {
    int age;
    double score;

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
    }

    // 重写equals方法
    @Override
    public boolean equals(Object obj) {
        // 1.满足自反性
        if (this == obj) {
            return true;
        }
        // 2.满足排它性,排除null和非同种类型的对象
        // 由于Class对象某个类型是唯一的,所以getClass方法可以用来判断两个引用指向的对象是否是同种类型对象
        if (obj == null || (getClass() != obj.getClass())) {
            return false;
        }
        // 代码如果能够运行到这里,说明obj肯定不是null并且它肯定是Student类的对象
        // 下面开始比较属性的取值,以满足对称性,传递性和一致性
        Student target = (Student) obj;
        if (age != target.age) {
            return false;
        }
        return score == target.score;
    }

}